package com.nulldev.util.net.tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.util.concurrent.ThreadLocalRandom;

import com.nulldev.util.math.MathUtil;

public class TCPUtil {
	static public void writeInt(int value, OutputStream output) throws IOException {
		if (value >>> 7 == 0) {
			output.write(value);
			return;
		}
		if (value >>> 14 == 0) {
			output.write((value & 0x7F) | 0x80);
			output.write(value >>> 7);
			return;
		}
		if (value >>> 21 == 0) {
			output.write((value & 0x7F) | 0x80);
			output.write(value >>> 7 | 0x80);
			output.write(value >>> 14);
			return;
		}
		if (value >>> 28 == 0) {
			output.write((value & 0x7F) | 0x80);
			output.write(value >>> 7 | 0x80);
			output.write(value >>> 14 | 0x80);
			output.write(value >>> 21);
			return;
		}
		output.write((value & 0x7F) | 0x80);
		output.write(value >>> 7 | 0x80);
		output.write(value >>> 14 | 0x80);
		output.write(value >>> 21 | 0x80);
		output.write(value >>> 28);
	}
	
	public static void writeLong(final long value, final OutputStream output0) throws IOException {
		final DataOutputStream output = new DataOutputStream(output0);
		output.writeLong(value);
//		if (value >>> 7 == 0) {
//			output.writeLong(value);
//			return;
//		}
//		if (value >>> 14 == 0) {
//			output.writeLong((value & 0x7F) | 0x80);
//			output.writeLong(value >>> 7);
//			return;
//		}
//		if (value >>> 21 == 0) {
//			output.writeLong((value & 0x7F) | 0x80);
//			output.writeLong(value >>> 7 | 0x80);
//			output.writeLong(value >>> 14);
//			return;
//		}
//		if (value >>> 28 == 0) {
//			output.writeLong((value & 0x7F) | 0x80);
//			output.writeLong(value >>> 7 | 0x80);
//			output.writeLong(value >>> 14 | 0x80);
//			output.writeLong(value >>> 21);
//			return;
//		}
//		output.writeLong((value & 0x7F) | 0x80);
//		output.writeLong(value >>> 7 | 0x80);
//		output.writeLong(value >>> 14 | 0x80);
//		output.writeLong(value >>> 21 | 0x80);
//		output.writeLong(value >>> 28);
	}

	/** Read an int using variable length encoding (1-5 bytes). */
	static public int readInt(InputStream input) throws IOException {
		int b = input.read();
		int result = b & 0x7F;
		if ((b & 0x80) == 0) return result;
		b = input.read();
		result |= (b & 0x7F) << 7;
		if ((b & 0x80) == 0) return result;
		b = input.read();
		result |= (b & 0x7F) << 14;
		if ((b & 0x80) == 0) return result;
		b = input.read();
		result |= (b & 0x7F) << 21;
		if ((b & 0x80) == 0) return result;
		b = input.read();
		return result | (b & 0x7F) << 28;
	}
	
	public static long readLong(final InputStream input0) throws IOException {
		final DataInputStream dis = new DataInputStream(input0);
		final long value = dis.readLong();
		return value;
	}
	
	public static int nextFreePort(int from, int to) {
	    int port = MathUtil.randInt(from, to);
	    while (true) {
	        if (isLocalPortFree(port)) {
	            return port;
	        } else {
	            port = ThreadLocalRandom.current().nextInt(from, to);
	        }
	    }
	}

	public static boolean isLocalPortFree(int port) {
	    try {
	        new ServerSocket(port).close();
	        return true;
	    } catch (IOException e) {
	        return false;
	    }
	}
}
